package com.wrupple.muba.catalogs.client.module.services.presentation.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import com.google.gwt.cell.client.Cell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent;
import com.google.gwt.user.cellview.client.ColumnSortEvent.AsyncHandler;
import com.google.gwt.user.cellview.client.ColumnSortList;
import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo;
import com.google.gwt.user.cellview.client.Header;
import com.google.gwt.user.cellview.client.TextHeader;
import com.google.gwt.view.client.HasData;
import com.google.inject.Inject;
import com.wrupple.muba.catalogs.client.CatalogFieldMap;
import com.wrupple.muba.catalogs.client.activity.process.task.CatalogInteractionState.Mode;
import com.wrupple.muba.catalogs.client.module.services.logic.CatalogDescriptionService;
import com.wrupple.muba.catalogs.client.module.services.logic.FieldConversionStrategyProvider;
import com.wrupple.muba.catalogs.client.module.services.logic.FieldDescriptionService;
import com.wrupple.muba.catalogs.client.module.services.presentation.FilterableDataProvider;
import com.wrupple.muba.catalogs.client.module.services.presentation.GenericDataDisplayDelegate;
import com.wrupple.muba.catalogs.client.widgets.fields.column.GenericColumn;
import com.wrupple.muba.catalogs.domain.CatalogEntry;
import com.wrupple.muba.common.client.FieldConversionStrategy;
import com.wrupple.muba.common.client.application.DataCallback;
import com.wrupple.muba.common.domain.FilterData;
import com.wrupple.muba.common.domain.FilterDataOrdering;
import com.wrupple.muba.widget.client.widgets.table.TableWithPager;
import com.wrupple.vegetate.domain.CatalogDescriptor;
import com.wrupple.vegetate.domain.FieldDescriptor;

public class GenericTableInitializer implements GenericDataDisplayDelegate {
	
	class SortHandler extends AsyncHandler {

		public SortHandler(HasData<?> arg0) {
			super(arg0);
		}

		@Override
		public void onColumnSort(ColumnSortEvent event) {
			columns = event.getColumnSortList();

			pushChangesToview(lastValue);

			super.onColumnSort(event);
		}

	}



	private class OnCatalogLoaded extends DataCallback<CatalogDescriptor> {
		private TableWithPager<CatalogEntry> table;

		public OnCatalogLoaded(TableWithPager<CatalogEntry> regreso) {
			this.table =  regreso;
		}

		@Override
		public void execute() {
			initializeTableColumns(table.getTable(), result);
		}
	}

	private CatalogDescriptionService descriptionService;
	private CatalogFieldMap fieldFactory;
	private FieldDescriptionService descriptor;
	protected HasData<?> display;
	private ColumnSortList columns;
	protected SimpleFilterableDataProviderImpl<?> dataProvider;
	private FilterData lastValue;
	private FieldConversionStrategyProvider conversionService;
	
	@Inject	
	public GenericTableInitializer(CatalogDescriptionService descriptionService, CatalogFieldMap fieldFactory,
			FieldDescriptionService descriptor,FieldConversionStrategyProvider conversionService) {
		super();
		this.descriptionService = descriptionService;
		this.fieldFactory = fieldFactory;
		this.descriptor = descriptor;
		this.conversionService=conversionService;
	}


	protected void initializeTableColumns(CellTable<CatalogEntry> table, CatalogDescriptor catalog) {
		final Map<String, FieldDescriptor> map = descriptor.getSummaryDescriptors(catalog);
		Collection<FieldDescriptor> summaries = map.values();

		Header<?> header;
		Column<CatalogEntry, ?> col;
		Cell cell;
		String keyField = catalog.getKeyField();
		FieldConversionStrategy conversion;
		for (FieldDescriptor field : summaries) {
			header = new TextHeader(field.getName());
			try {
				conversion = conversionService.getFieldConversionStrategy(field.getId(), catalog);
				cell = fieldFactory.get(field.getWidget()).createCell(null, null, field, Mode.READ);
				col = new GenericColumn(field.getId(),cell,conversion);
			} catch (Exception e) {
				col = null;
				GWT.log("Attempt to create column failed. catalgog:" + catalog.getName() + " field:" + field.getId()
						+ " widget:" + field.getWidget(), e);
			}
			if (col != null) {
				col.setSortable(true);
				table.addColumn(col, header);
			}
		}
		
		table.addColumnSortHandler(new SortHandler(table));
	}

	@Override
	public void onValueChange(ValueChangeEvent<FilterData> event) {
		pushChangesToview(event.getValue());
		display.setVisibleRangeAndClearData(display.getVisibleRange(), true);
	}
	
	void pushChangesToview(FilterData filter) {
		this.lastValue = filter;
		
		if (columns != null) {
			ColumnSortInfo columnInfo;
			Column<?, ?> column;
			GenericColumn catalogColumn;
			ArrayList<FilterDataOrdering> order = new ArrayList<FilterDataOrdering>(columns.size());
			FilterDataOrdering columnOrder;
			for (int i = 0; i < columns.size(); i++) {
				columnInfo = columns.get(0);
				column = columnInfo.getColumn();
				try {
					catalogColumn = (GenericColumn) column;
					columnOrder = new FilterDataOrdering();
					columnOrder.setAscending(columnInfo.isAscending());
					columnOrder.setField(catalogColumn.getFieldId());
					order.add(columnOrder);
				} catch (Exception e) {
					GWT.log("I tried, i swear, but i dont know how to sort this type of column", e);
				}
			}

			filter.setOrder(order);
		}

		pushFilterChangesToView(filter);
	}
	public void pushFilterChangesToView(FilterData filter) {
		this.dataProvider.setFilter(filter);
		if(!dataProvider.getDataDisplays().contains(display)){
			//the reason display and initializer have to match
			HasData caster = display;
			dataProvider.addDataDisplay(caster);
		}
		
	}


	@Override
	public <T> void initialize(String catalogid, HasData<T> display,
			FilterableDataProvider<T> provider) {
		this.dataProvider=(SimpleFilterableDataProviderImpl<?>) provider;
		this.display = display;
		dataProvider.setCatalog(catalogid);
		if(!dataProvider.getDataDisplays().contains(display)){
			provider.addDataDisplay(display);
		}
		
		if(display instanceof TableWithPager){
			descriptionService.loadCatalogDescriptor(catalogid, new OnCatalogLoaded((TableWithPager<CatalogEntry>) display));
		}else{
			
		}
	}

}
